package com.zjj.learn.javaplus.pkg03.demo301;

public class TestDemo301_3 {


    public static void main(String[] args) {
//        Object str = new String();
//        String str1 = (String) new Object();

        Animal1 a = new Wolf1();
        a.run();
        // a.catchSheep(); // 报错！

        // 1.把动物类型的变量a 转换成 真实的狼类型
        Wolf1 w = (Wolf1) a;
        w.catchSheep();

        // 2.多态下类型转换异常问题研究（重点）
        Animal1 a1 = new Cat1();
        //Wolf1 w1 = (Wolf1) a1; // 编译阶段没有报错！在运行阶段出现ClassCastException类型转换成！
        if (a1 instanceof Cat1) {
            Cat1 c1 = (Cat1) a1;
            c1.catchMouse();
        } else if (a1 instanceof Wolf1) {
            Wolf1 w1 = (Wolf1) a1;
            w1.catchSheep();
        }
    }

    /**
     * 引用类型的类型转化 ，instanceof 关键字的使用
     * 回顾：
     *    1、小范围类型的变量或者值可以直接转化成大范围类型的变量或者值；
     *       例如：Object str = new String();
     *    2、大范围类型的变量或者值若需要转化成小范围，就必须使用强制类型转化；
     *       例如：String str1 = (String) new Object();
     *
     * 一：自动转化
     * 在引用类型的转化思想也是一样的：【父类（或者接口）的类型范围 > 子类（或实现类）的类型范围】
     *   所以： Animal > Cat
     *         Animal animal = new Cat(); 类型直接转化了
     *
     * 引用数据类型的自动类型转换语法：
     *      1.子类类型的对象或者变量可以自动类型转换赋值给父类类型的变量。
     *
     * 总结：
     * 自动转化并不能够解决多态的劣势（使用具体对象的特殊方法）
     *
     *
     *
     * 二：强制类型转化
     *   强制类型转化语法：
     *      父类类型的变量或者对象必须强制转化成子类类型的变量或者对象【大范围项小范围转化】
     *
     *   强制类型转化格式
     *      类型【小范围】 变量名称 = (类型) new 对象或者变量【大范围】 ；如 String str1 = (String) new Object();
     *      例如：给出如下三个类
     *           {@link com.zjj.learn.javaplus.pkg03.demo301.Animal1}
     *           {@link com.zjj.learn.javaplus.pkg03.demo301.Wolf1}
     *           {@link com.zjj.learn.javaplus.pkg03.demo301.Cat1}
     *
     *           执行以下代码：
     *               Animal1 a = new Wolf1();
     *               a.run();
     *               // a.catchSheep(); // 报错！
     *
     *               // 1.把动物类型的变量a 转换成 真实的狼类型
     *               Wolf1 w = (Wolf1) a;
     *               w.catchSheep();  //成功执行
     *
     *   注意：只要有继承或者实现关系的两个类型就可以强制类型转化，编译期间一定不报错，但是运行期间可能或抛出 ClassCastException 异常
     *        String str1 = (String) new Object(); 在运行时就会报错
     *
     *   建议：在进行强制类型转化时，首先用 instanceof 关键字判断是否可以成功转化，避免出现 ClassCastException 异常
     *        例如代码：
     *
     *
     *         Animal1 a1 = new Cat1();
     *         //Wolf1 w1 = (Wolf1) a1; // 编译阶段没有报错！在运行阶段出现ClassCastException类型转换成！
     *         if(a1 instanceof Cat1){
     *             // a1 instanceof Cat1 返回 true
     *             Cat1 c1 = (Cat1) a1;
     *             c1.catchMouse();
     *         }else if(a1 instanceof Wolf1){
     *             // a1 instanceof Wolf1 返回 false，不会执行下面两行代码
     *             Wolf1 w1 = (Wolf1) a1;
     *             w1.catchSheep();
     *         }
     *
     *   总结：
     *       有继承/实现关系的两个类型就可以进行强制类型转换，编译阶段一定不报错！
     *         但是运行阶段可能出现：类型转换异常 ClassCastException
     *         Java建议在进行强制类型转换之前先判断变量的真实类型，再强制类型转换!
     *         变量 instanceof 类型： 判断前面的变量是否是后面的类型或者其子类类型才会返回true
     **/
}

class Wolf1 extends Animal1 {
    @Override
    public void run() {
        System.out.println("狼跑的飞快~~~");
    }

    public void catchSheep() {
        System.out.println("🐺抓🐏");
    }
}

class Cat1 extends Animal1 {
    @Override
    public void run() {
        System.out.println("猫跑的贼快~~~");
    }

    public void catchMouse() {
        System.out.println("🐱抓🐀~~");
    }
}

class Animal1 {
    public void run() {
        System.out.println("动物可以跑~~");
    }
}
